package com.syp.auth.service.base.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.syp.auth.dao.po.AppEntity;
import com.syp.auth.dao.po.AppMemberEntity;
import com.syp.auth.dao.po.UserEntity;
import com.syp.auth.dao.repository.AppMemberRepository;
import com.syp.auth.dao.repository.AppRepository;
import com.syp.auth.dao.repository.ResourceRepository;
import com.syp.auth.dao.repository.UserRepository;
import com.syp.auth.domain.vo.AppVo;
import com.syp.auth.domain.vo.UserVo;
import com.syp.auth.service.base.AppServiceI;


@Service("appService")
public class AppServiceImpl implements AppServiceI {

	@Autowired
	private AppRepository appRepository;
	@Autowired
	private ResourceRepository resourceRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private AppMemberRepository appMemberRepository;

	@Transactional
	@Override
	public void add(AppVo app) {
		AppEntity ae = new AppEntity();
		BeanUtils.copyProperties(app, ae);
		app.setCreateTime(Calendar.getInstance().getTime());
		app.setLastUpdate(Calendar.getInstance().getTime());
		ae = this.appRepository.save(ae);
		
		//插入应用成员
		if(app.getAppMemberIds() != null && !app.getAppMemberIds().isEmpty()){
			List<UserEntity> appMembers = this.userRepository.getByLimitedIdList(app.getAppMemberIds());
			List<AppMemberEntity> amList = new LinkedList<>();
			for(UserEntity ue : appMembers){
				AppMemberEntity ame = new AppMemberEntity();
				ame.setAppId(ae.getId());
				ame.setAppCode(ae.getAppCode());
				ame.setUserId(ue.getId());
				ame.setUserCode(ue.getUserCode());
				amList.add(ame);
			}
			this.appMemberRepository.save(amList);
		}
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void delete(Long id) {
		this.appRepository.delete(id);
		this.appMemberRepository.deleteBatchByAppId(id);
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void deleteBatch(List<Long> ids) {
		this.appRepository.deleteBatch(ids);
		this.appMemberRepository.deleteBatchByAppIdList(ids);
	}

	@Transactional(rollbackOn = { RuntimeException.class })
	@Override
	public void edit(AppVo app) {
		AppEntity appEntity = this.appRepository.findOne(app.getId());
		appEntity.setAppCode(app.getAppCode());
		appEntity.setAppName(app.getAppName());
		appEntity.setVerifyStyle(app.getVerifyStyle());
		appEntity.setSessionKeepMins(app.getSessionKeepMins());
		appEntity.setDescription(app.getDescription());
		appEntity.setLastUpdate(Calendar.getInstance().getTime());
		this.appRepository.save(appEntity);
		
		//插入应用成员
		if(app.getAppMemberIds() != null && !app.getAppMemberIds().isEmpty()){
			this.appMemberRepository.deleteBatchByAppId(appEntity.getId());
			List<UserEntity> appMembers = this.userRepository.getByLimitedIdList(app.getAppMemberIds());
			List<AppMemberEntity> amList = new LinkedList<>();
			for(UserEntity ue : appMembers){
				AppMemberEntity ame = new AppMemberEntity();
				ame.setAppId(appEntity.getId());
				ame.setAppCode(appEntity.getAppCode());
				ame.setUserId(ue.getId());
				ame.setUserCode(ue.getUserCode());
				amList.add(ame);
			}
			this.appMemberRepository.save(amList);
		}
	}

	@Override
	public AppVo get(Long id) {
		AppVo app = new AppVo();
		AppEntity appEntity = this.appRepository.findOne(id);
		BeanUtils.copyProperties(appEntity, app);
		
		List<AppMemberEntity> amList = this.appMemberRepository.getByAppId(appEntity.getId());
		if(amList != null && !amList.isEmpty()){
			List<Long> userIdList = new LinkedList<>();
			for(AppMemberEntity am : amList){
				userIdList.add(am.getUserId());
			}
			List<UserEntity> userList = this.userRepository.getByLimitedIdList(userIdList);
			List<UserVo> userAsMemberList = new LinkedList<>();
			for(UserEntity u : userList){
				UserVo user = new UserVo();
				user.setId(u.getId());
				user.setUserCode(u.getUserCode());
				userAsMemberList.add(user);
			}
			app.setAppMembers(userAsMemberList);
		}
		return app;
	}

	@Override
	public AppVo getByAppCode(String appCode) {
		AppVo app = null;
		AppEntity appEntity = this.appRepository.getByAppCode(appCode);
		if (appEntity != null) {
			app = new AppVo();
			BeanUtils.copyProperties(appEntity, app);
		}
		return app;
	}

	@Override
	public List<AppVo> list(final AppVo app) {
		Specification<AppEntity> spec = new Specification<AppEntity>() {
			@Override
			public Predicate toPredicate(Root<AppEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> pList = new ArrayList<>();
				if (!StringUtils.isEmpty(app.getAppCode())) {
					pList.add(cb.like(root.get("appCode").as(String.class), "%" + app.getAppCode().trim() + "%"));
				}
				if (!StringUtils.isEmpty(app.getAppName())) {
					pList.add(cb.like(root.get("appName").as(String.class), "%" + app.getAppName().trim() + "%"));
				}
				return cb.and(pList.toArray(new Predicate[pList.size()]));
			}
		};

		String order = app.getOrder() == null ? "desc" : app.getOrder();
		String sortColumn = app.getSort() == null ? "id" : app.getSort();
		Sort sort = new Sort(Sort.Direction.fromString(order), sortColumn);
		List<AppEntity> allList = this.appRepository.findAll(spec, sort);

		List<AppVo> list = new LinkedList<>();
		if (allList != null && !allList.isEmpty()) {
			for (AppEntity ae : allList) {
				AppVo appVo = new AppVo();
				BeanUtils.copyProperties(ae, appVo);
				list.add(appVo);
			}
		}
		return list;
	}

	@Override
	public List<AppVo> dropdownListItems(final String param) {
		Specification<AppEntity> spec = new Specification<AppEntity>() {
			@Override
			public Predicate toPredicate(Root<AppEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate p = null;
				if (param != null && !param.trim().isEmpty()) {
					p = cb.and(cb.like(root.get("appCode").as(String.class), "%" + param.trim() + "%"));
					p = cb.or(p, cb.like(root.get("appName").as(String.class), "%" + param.trim() + "%"));
				}
				return p;
			}
		};
		Sort sort = new Sort(Sort.Direction.fromString("desc"), "id");
		List<AppEntity> allList = this.appRepository.findAll(spec, sort);

		List<AppVo> list = new LinkedList<>();
		if (allList != null && !allList.isEmpty()) {
			for (AppEntity ae : allList) {
				AppVo appVo = new AppVo();
				BeanUtils.copyProperties(ae, appVo);
				list.add(appVo);
			}
		}
		return list;
	}

	@Override
	public Page<AppVo> pagelist(final AppVo app) {
		Specification<AppEntity> spec = new Specification<AppEntity>() {

			@Override
			public Predicate toPredicate(Root<AppEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> pList = new ArrayList<>();
				if (!StringUtils.isEmpty(app.getAppCode())) {
					pList.add(cb.like(root.get("appCode").as(String.class), "%" + app.getAppCode().trim() + "%"));
				}
				if (!StringUtils.isEmpty(app.getAppName())) {
					pList.add(cb.like(root.get("appName").as(String.class), "%" + app.getAppName().trim() + "%"));
				}
				return cb.and(pList.toArray(new Predicate[pList.size()]));
			}
		};

		String order = app.getOrder() == null ? "desc" : app.getOrder();
		String sortColumn = app.getSort() == null ? "id" : app.getSort();
		Sort sort = new Sort(Sort.Direction.fromString(order), sortColumn);
		Pageable pageable = new PageRequest(app.getPage() - 1, app.getRows(), sort);
		Page<AppEntity> page = this.appRepository.findAll(spec, pageable);

		List<AppVo> list = new LinkedList<>();
		if (page.hasContent()) {
			for (AppEntity ae : page.getContent()) {
				AppVo appVo = new AppVo();
				BeanUtils.copyProperties(ae, appVo);
				list.add(appVo);
			}
		}
		return new PageImpl<>(list, pageable, page.getTotalElements());
	}

	@Override
	public boolean checkAppCodeUnique(String appcode) {
		boolean unique = false;

		AppEntity u = this.appRepository.getByAppCode(appcode);
		if (u == null) {
			unique = true;
		}
		return unique;
	}

	@Override
	public boolean checkAppCanbeRemovedById(Long appid) {
		long appResCount = this.resourceRepository.countByAppId(appid);

		return appResCount == 0;
	}

}
